package com.example.infrastructure.excel;

import cn.idev.excel.EasyExcel;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.read.listener.ReadListener;
import cn.idev.excel.util.ListUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Consumer;

/**
 * Excel工具类
 */
@Slf4j
public class ExcelUtils {
    
    /**
     * 导出Excel
     */
    public static <T> void export(HttpServletResponse response, String fileName, 
                                  String sheetName, Class<T> clazz, List<T> data) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName + ".xlsx");
            
            EasyExcel.write(response.getOutputStream(), clazz)
                    .sheet(sheetName)
                    .doWrite(data);
        } catch (IOException e) {
            log.error("Excel导出失败", e);
            throw new RuntimeException("Excel导出失败", e);
        }
    }
    
    /**
     * 导入Excel
     */
    public static <T> List<T> importExcel(MultipartFile file, Class<T> clazz, Consumer<T> validator) {
        List<T> list = ListUtils.newArrayList();
        try {
            EasyExcel.read(file.getInputStream(), clazz, new ReadListener<T>() {
                @Override
                public void invoke(T data, AnalysisContext context) {
                    if (validator != null) {
                        validator.accept(data);
                    }
                    list.add(data);
                }
                
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    log.info("Excel读取完成，共{}条数据", list.size());
                }
            }).sheet().doRead();
        } catch (IOException e) {
            log.error("Excel导入失败", e);
            throw new RuntimeException("Excel导入失败", e);
        }
        return list;
    }
    
    /**
     * 导入Excel（带批处理）
     */
    public static <T> void importExcelWithBatch(MultipartFile file, Class<T> clazz, 
                                                int batchSize, Consumer<List<T>> batchProcessor) {
        try {
            EasyExcel.read(file.getInputStream(), clazz, new ReadListener<T>() {
                private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(batchSize);
                
                @Override
                public void invoke(T data, AnalysisContext context) {
                    cachedDataList.add(data);
                    if (cachedDataList.size() >= batchSize) {
                        batchProcessor.accept(cachedDataList);
                        cachedDataList = ListUtils.newArrayListWithExpectedSize(batchSize);
                    }
                }
                
                @Override
                public void doAfterAllAnalysed(AnalysisContext context) {
                    if (!cachedDataList.isEmpty()) {
                        batchProcessor.accept(cachedDataList);
                    }
                    log.info("Excel批量处理完成");
                }
            }).sheet().doRead();
        } catch (IOException e) {
            log.error("Excel批量导入失败", e);
            throw new RuntimeException("Excel批量导入失败", e);
        }
    }
}
